﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Amazon.S3;
using Amazon.S3.Model;
using System.IO;
using System.Globalization;

namespace NAntExt.Aws
{
    /// <summary>
    /// Represents a file on S3.
    /// </summary>
    public class S3File
    {
        public static void Delete(AmazonS3Client client, string bucketName, string key)
        {
            // delete the file from s3
            var deleteRequest = new DeleteObjectRequest();
            deleteRequest.WithBucketName(bucketName);
            deleteRequest.WithKey(key);
            using (var deleteResponse = client.DeleteObject(deleteRequest))
            {
                // TODO: check for success
            }
        }

        public static string CalculateETag(string file)
        {
            using (var fileStream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                var etag = Amazon.S3.Util.AmazonS3Util.GenerateChecksumForStream(fileStream, false);
                return etag;
            }            
        }

        public static S3File Get(AmazonS3Client client, string bucketName, string key)
        {
            if (client == null)
            {
                throw new System.ArgumentNullException("client");
            }

            if (bucketName == null)
            {
                throw new ArgumentNullException("bucketName");
            }
            else if (bucketName == string.Empty)
            {
                throw new ArgumentOutOfRangeException("bucketName", "Value cannot be empty.");
            }

            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            else if (key == string.Empty)
            {
                throw new ArgumentOutOfRangeException("key", "Value cannot be empty.");
            }

            try
            {
                GetObjectMetadataRequest metadataRequest = new GetObjectMetadataRequest();
                metadataRequest.WithBucketName(bucketName);
                metadataRequest.WithKey(key);

                using (GetObjectMetadataResponse metadataResponse = client.GetObjectMetadata(metadataRequest))
                {
                    return new S3File()
                    {
                        BucketName = bucketName,
                        Key = key,
                        Length = metadataResponse.ContentLength,
                        ETag = metadataResponse.ETag.Trim('"')
                    };
                }
            }
            catch (AmazonS3Exception ex)
            {
                if (ex.Message == "The specified key does not exist")
                    return null;
                else
                    throw;
            }

        }

        public static S3File Upload(AmazonS3Client client, string bucketName, string key, FileInfo file)
        {
            if (client == null)
            {
                throw new System.ArgumentNullException("client");
            }

            if (bucketName == null)
            {
                throw new ArgumentNullException("bucketName");
            }
            else if (bucketName == string.Empty)
            {
                throw new ArgumentOutOfRangeException("bucketName", "Value cannot be empty.");
            }

            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            else if (key == string.Empty)
            {
                throw new ArgumentOutOfRangeException("key", "Value cannot be empty.");
            }

            if (file == null)
            {
                throw new System.ArgumentNullException("file");
            }
                                    
            // put a more complex object with some metadata and http headers.
            PutObjectRequest filePutObjectRequest = new PutObjectRequest();

            filePutObjectRequest.WithBucketName(bucketName);
            filePutObjectRequest.WithKey(key);
            filePutObjectRequest.WithFilePath(file.FullName);
            
            using (S3Response responseWithMetadata = client.PutObject(filePutObjectRequest))
            {
                return new S3File()
                {
                    BucketName = bucketName,
                    Key = key,
                    ETag = responseWithMetadata.Headers["ETag"].Trim('"'),
                    Length = file.Length,
                };
            }

        }

        /// <summary>
        /// Initializes a new instance.
        /// </summary>
        private S3File()
        {
        }

        /// <summary>
        /// The name of the bucket the file resides within Amazon.
        /// </summary>
        public string BucketName { get; private set; }

        /// <summary>
        /// The Amazon key for the file.
        /// </summary>
        public string Key { get; private set; }

        /// <summary>
        /// The Amazon etag for the file.
        /// </summary>
        public string ETag { get; private set; }

        /// <summary>
        /// The size of the file.
        /// </summary>
        public long Length { get; private set; }

        /// <summary>
        /// Compares the S3File to a local File to determine if they are equal.
        /// </summary>
        /// <param name="file">The local file to compare.</param>
        /// <returns>Returns <c>true</c>, if they equal, else <c>false</c>, if they are not equal.</returns>
        public bool Equals(FileInfo file)
        {
            return string.Equals(CalculateETag(file.FullName), this.ETag, StringComparison.InvariantCultureIgnoreCase)
                && file.Length == this.Length;
        }
        
    }
}
